{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipy.optimize"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Уровень 0:\n",
    "\n",
    "Посчитайте частные производные функций:\n",
    "\n",
    "1) $f(x,y)=2x^2y^3 + 1/x + y^2x + 7$, а для этой функции также градиент в точке $(1,2)$\n",
    "\n",
    "$f'x=4xy^3 - 1/x^2 + y^2$\n",
    "\n",
    "$f'y=6x^2y^2 + 2yx $\n",
    "\n",
    "2) $f(x,y)=x^2y - sin(xy) + cos(x^2) + 6y$\n",
    "\n",
    "$f'x=2xy - y*cos(xy) - 2x*sin(x^2)$\n",
    "\n",
    "$f'y=x^2 - x*cos(xy) + 6$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([35.00000024, 28.00000024])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def func(x):\n",
    "    return 2*(x[0]**2)*(x[1]**3) + 1/x[0] + (x[1]**2)*x[0] + 7\n",
    "\n",
    "eps = eps = np.sqrt(np.finfo(float).eps)\n",
    "scipy.optimize.approx_fprime((1,2), func, epsilon=[eps,eps])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Уровень 1:\n",
    "\n",
    "Градиентный спуск своими руками:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Количество циклов поиска минимума функции: 108\n",
      "Минимум достигается в:  [-4.03300102e-09 -6.15421878e-10]\n",
      "Значение функции в минимуме:  1.664384130055696e-17\n",
      "Значение градиента в точке минимума: [8.54394895e-09 1.70878968e-08]\n"
     ]
    }
   ],
   "source": [
    "def f(x):\n",
    "    return (x[0]**2) + (x[1]**2)\n",
    "\n",
    "x = np.array([100, 200])\n",
    "learning_rate = 0.1\n",
    "eps = np.sqrt(np.finfo(float).eps)\n",
    "func_values = []\n",
    "\n",
    "counter = 0\n",
    "while True:\n",
    "    \n",
    "    counter += 1\n",
    "    func_value = f(x)\n",
    "    func_values.append(func_value)\n",
    "    grad = scipy.optimize.approx_fprime(x, f, epsilon=[eps,eps])\n",
    "    x = x - learning_rate * grad\n",
    "    new_func_value = f(x)\n",
    "    if new_func_value < func_value:\n",
    "        func_value = new_func_value\n",
    "    else:\n",
    "        print('Количество циклов поиска минимума функции:', counter)\n",
    "        break\n",
    "    \n",
    "print(\"Минимум достигается в: \", x)\n",
    "print(\"Значение функции в минимуме: \", f(x))\n",
    "print('Значение градиента в точке минимума:', grad)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Получили значение градиента близкое к 0, предполагаем, что наше решение верное.\n",
    "Проверимся с помощью scipy.optimize.minimize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization terminated successfully.\n",
      "         Current function value: 0.000000\n",
      "         Iterations: 59\n",
      "         Function evaluations: 112\n",
      "Минимум достигается в:  [ 3.12645005e-05 -2.53507530e-05]\n",
      "Значение функции в минимуме:  1.620129666631487e-09\n"
     ]
    }
   ],
   "source": [
    "f_min = scipy.optimize.minimize(f, np.array([100, 200]), method='Nelder-Mead', options={'disp': True})\n",
    "print(\"Минимум достигается в: \", f_min.x)\n",
    "print(\"Значение функции в минимуме: \", f(f_min.x))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
